package com.gxa.employment.service.impl;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxa.employment.common.JsonConvert;
import com.gxa.employment.common.ManagerThreadLocal;
import com.gxa.employment.entity.dto.LoginDto;
import com.gxa.employment.entity.dto.PageWithPhoneDto;
import com.gxa.employment.entity.dto.UpdatePwdDto;
import com.gxa.employment.entity.pojo.Manager;
import com.gxa.employment.entity.vo.PageVo;
import com.gxa.employment.exception.BizException;
import com.gxa.employment.exception.ErrorMessage;
import com.gxa.employment.mapper.ManagerMapper;
import com.gxa.employment.mapper.PermissionMapper;
import com.gxa.employment.mapper.RoleMapper;
import com.gxa.employment.service.ManagerService;
import com.gxa.employment.utils.JwtUtil;
import com.gxa.employment.utils.SMSUtil;

import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.UUID;

/**
 * <p>
 * 管理员 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-03-25
 */
@Service
@Transactional(rollbackFor = Throwable.class)
public class ManagerServiceImpl extends ServiceImpl<ManagerMapper, Manager> implements ManagerService {
    //阿里云短信服务
    private static final String TEMPLATE_CODE = "SMS_480135329";

    @Autowired
    private ManagerMapper managerMapper;
    @Autowired
    RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    RedissonClient redissonClient;

    /**
     * 登录方法
     *
     * @param loginDto
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> login(LoginDto loginDto) throws Exception {
        //校验合法性使用的注解

        String phone = loginDto.getPhone();
        String pwd = loginDto.getPwd();
        LambdaQueryWrapper<Manager> lambdaQuery = Wrappers.lambdaQuery(Manager.class);
        lambdaQuery.eq(Manager::getManagerPhone, phone);

        Manager manager = getOne(lambdaQuery);
        //手机号是否存在
        if (manager == null) {
            throw new BizException(ErrorMessage.PHONE_OR_PWD_ERROR);
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        //验证密码是否正确
        if (!encoder.matches(pwd, manager.getManagerPwd())) {
            throw new BizException(ErrorMessage.PHONE_OR_PWD_ERROR);
        }

        //生成token
        //token的数据
        HashMap<String, String> map = new HashMap<>();
        //返回前端的数据
        HashMap<String, Object> returnMap = new HashMap<>();
        returnMap.put("manager", manager);
        map.put("manager", JsonConvert.write(manager));

        //获取角色id   存储该管理员的角色id
        String roleId = roleMapper.selectByManager(manager.getManagerId()).toString();
        map.put("roleId", roleId);
        //生成token
        String token = JwtUtil.generate(map);

        //返回token
        returnMap.put("token", token);

        //查询菜单、按钮、API等权限信息
        //查询权限信息
        Set<String> permissions = permissionMapper.selectUrlById(manager.getManagerId(),"API");
        Set<String> buttons = permissionMapper.selectUrlById(manager.getManagerId(),"按钮");
        Set<String> menus = permissionMapper.selectUrlById(manager.getManagerId(),"菜单");


        //生成、添加权限  储存在redis上
        SetOperations<String, Object> opsForSet = redisTemplate.opsForSet();
        Set<Object> members = opsForSet.members("role:" + roleId);
        if (members==null || members.isEmpty()) {

            //过滤非法字符
            Object[] array = permissions.stream().filter(s ->s!=null && s.contains("/")).toArray();
            //添加到redis中
            opsForSet.add("role:" + roleId, array);
        }

        //双token判断
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        if(opsForValue.get("token:" + phone) == null){
            opsForValue.set("token:" + phone, token);
        }
        returnMap.put("permissions", permissions);
        returnMap.put("buttons", buttons);
        returnMap.put("menus", menus);
        return returnMap;
    }

    /**
     * 发送短信验证码
     *
     * @param phone 接收短信的手机号
     * @throws BizException 业务异常
     * @throws ClientException 客户端异常
     */
    @Override
    public void sms(String phone) throws BizException, ClientException {
        Manager byPhone = getByPhone(phone);
        //判断手机号是否存在
        if (byPhone != null) {
            throw new BizException(ErrorMessage.DUPLICATE_DATA);
        }

        //生成验证码 6为随机数字
        String code = SMSUtil.getNumberMsgCode();
        SendSmsResponse sendSmsResponse = SMSUtil.sendSms(phone, TEMPLATE_CODE, code);
        //判断是否生成成功
        if (!"OK".equals(sendSmsResponse.getCode())) {
            throw new BizException(ErrorMessage.SMS_SEND_ERROR);
        }
        redisTemplate.opsForValue().set("code:" + phone, code, 60 * 10);
    }

    @Override
    public void updatePwd(UpdatePwdDto dto) throws BizException {
        String originalPwd  = dto.getOriginalPwd();
        String newPwd = dto.getNewPwd();
        //判断输入是否为null
        if (StringUtils.isBlank(newPwd) || StringUtils.isBlank(originalPwd)) {
            throw new BizException(ErrorMessage.INPUT_EMPTY);
        }
        //新密码不能与原密码相同
        if(StringUtils.equals(newPwd,originalPwd)){
            throw new BizException(ErrorMessage.PHONE_OR_PWD_ERROR);
        }
        //从 ManagerThreadLocal 获取当前登录的管理员信息
        Manager manager = getById(ManagerThreadLocal.get().getManagerId());

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        //验证密码是否正确
        if (!encoder.matches(originalPwd, manager.getManagerPwd())) {
            throw new BizException(ErrorMessage.PHONE_OR_PWD_ERROR);
        }
        //设置新密码
        manager.setManagerPwd(encoder.encode(newPwd));
        //更新管理员信息
        updateById(manager);
        //清除缓存  token
        redisTemplate.delete("token:" + manager.getManagerPhone());
    }


    /**
     * 注册方法
     *
     * @throws Exception
     */
    @Override
    public void register(LoginDto loginDto) throws Exception {
        String phone = loginDto.getPhone();
        //检验手机号是否存在
        Manager byPhone = getByPhone(phone);
        if (byPhone != null) {
            throw new BizException(ErrorMessage.DUPLICATE_DATA);
        }
        //校验验证码
        String code = (String) redisTemplate.opsForValue().get("code:" + phone);
        if (!StringUtils.equals(code, loginDto.getPwd())) {
            throw new BizException(ErrorMessage.PHONE_OR_PWD_ERROR);
        }
        //删除验证码
        redisTemplate.delete("code:" + phone);

        //添加用户
        Manager manager = new Manager();
        manager.setManagerPhone(phone);
        add(manager);
    }

    /**
     * 添加管理员
     *
     * @param manager
     * @throws Exception
     */
    @Override
    public void add(Manager manager) {
        //添加默认密码  手机号后六位
        String managerPwd = manager.getManagerPwd();
        if (managerPwd == null) {
            managerPwd = manager.getManagerPhone().substring(5);
        }
        //加密密码
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        manager.setManagerPwd(encoder.encode(managerPwd));
        managerMapper.insert(manager);
        //分配默认权限
        roleMapper.allocateRole(manager.getManagerId(), 2);
    }


    /**
     * 模糊查询方法(分页)
     *
     * @param dto
     * @return
     */
    @Override
    public PageVo<Manager> getByPage(PageWithPhoneDto dto) {
        String phone = dto.getPhone();
        String name = dto.getName();

        //查询条件
        LambdaQueryWrapper<Manager> lambdaQuery = Wrappers.lambdaQuery(Manager.class);
        lambdaQuery.like(StringUtils.isNotEmpty(phone), Manager::getManagerPhone, phone)
                .like(StringUtils.isNotEmpty(name), Manager::getManagerName, name);
        //分页
        IPage<Manager> page = new Page<>(dto.getPage(), dto.getSize());

        page(page, lambdaQuery);
        return new PageVo<>(page.getTotal(), page.getRecords());
    }

    /**
     * 根据手机号查询数据
     *
     * @param phone
     * @return
     * @throws Exception
     */
    public Manager getByPhone(String phone) throws BizException {
        if (phone == null) {
            throw new BizException(ErrorMessage.INPUT_EMPTY);
        }
        LambdaQueryWrapper<Manager> lambdaQuery = Wrappers.lambdaQuery(Manager.class);
        lambdaQuery.eq(Manager::getManagerPhone, phone);
        return getOne(lambdaQuery);
    }

}
